package controller;

/*
 * Action for creating a new survey as a researcher.
 */

import formbeans.BasicNameForm;
import formbeans.BasicSelectForm;
import formbeans.SendSurveyForm;
import helper.UserType;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.mybeans.dao.DAOException;
import org.mybeans.form.FormBeanException;
import org.mybeans.form.FormBeanFactory;

import databeans.Entity;
import databeans.EntityClass;
import databeans.MailingList;
import databeans.MailingListData;
import databeans.Survey;
import databeans.User;
import model.EntityClassDAO;
import model.EntityDAO;
import model.MailingListDAO;
import model.MailingListDataDAO;
import model.Model;
import model.SurveyDAO;
import model.UserDAO;

public class MailingListAction extends Action {
	private FormBeanFactory<SendSurveyForm> formBeanFactory = FormBeanFactory.getInstance(SendSurveyForm.class);
	private FormBeanFactory<BasicNameForm> bnformBeanFactory = FormBeanFactory.getInstance(BasicNameForm.class);
	private FormBeanFactory<BasicSelectForm> bsformBeanFactory = FormBeanFactory.getInstance(BasicSelectForm.class);
	private UserDAO userDAO;
	private SurveyDAO surveyDAO;
	private MailingListDAO mlDAO;
	private MailingListDataDAO mldDAO;
	private EntityClassDAO ecDAO;
	private EntityDAO entityDAO;
	
	public MailingListAction(Model model) {
		userDAO = model.getUserDAO();
		surveyDAO = model.getSurveyDAO();
		mlDAO = model.getMailingListDAO();
		mldDAO = model.getMailingListDataDAO();
		ecDAO = model.getEntityClassDAO();
		entityDAO = model.getEntityDAO();
	}
	
    public String getName() {
		return "mailinglist.do";
	}
    
    public String perform(HttpServletRequest request) {

        List<String> errors = new ArrayList<String>();
        request.setAttribute("errors",errors);
        
    	// First, validate whether researcher is accessing this
    	HttpSession session = request.getSession(false);
    	User user = (User) session.getAttribute("user");
    	
    	if (user.getType() != UserType.RESEARCHER) {
    		errors.add("You are not a researcher!");
    		return "homepage.jsp";
    	}
    	
    	// Importing Mailing List Data file
    	if (request.getContentType() != null && request.getContentType().indexOf("multipart/form-data") >= 0) {
    		/*ServletContext sc = session.getServletContext();
    		String filePath = sc.getInitParameter("file-upload");*/
    		
    		DiskFileItemFactory factory = new DiskFileItemFactory();
    		factory.setSizeThreshold(512 * 1024 * 1024);
    		factory.setRepository(new File("C:\\temp"));
    		
    		ServletFileUpload upload = new ServletFileUpload(factory);
    		upload.setSizeMax(512 * 1024 * 1024);
    		
    		try {
    			@SuppressWarnings("unchecked")
				List<FileItem> fileitems = upload.parseRequest(request);
    			Iterator<FileItem> it = fileitems.iterator();
    			
    			while (it.hasNext()) {
    				FileItem fi = (FileItem)it.next();
    				if (!fi.isFormField()) {
    					String fieldName = fi.getFieldName();
    					String fileName = fi.getName();
    					boolean isInMemory = fi.isInMemory();
    					long sizeInBytes = fi.getSize();
    					
    					/*File file;
    					
    					if (fileName.lastIndexOf("\\") >= 0) {
    						file = new File(filePath + fileName.substring(fileName.lastIndexOf("\\")));
    					}
    					else {
    						file = new File(filePath + fileName.substring(fileName.lastIndexOf("\\") + 1));
    					}*/
    					
    					InputStream uploadedStream = fi.getInputStream();
    					
    					BufferedReader input = new BufferedReader(new InputStreamReader(uploadedStream));
    					Scanner scanner = new Scanner(input);
    					String[] header = scanner.nextLine().split(",");
    					System.out.println("header length = " + header.length);
    					if (header.length != 2) {
    						throw new IllegalArgumentException("Header must have two entries (username, email).");
    					}
    					if (!(header[0].equalsIgnoreCase("username") || header[0].equalsIgnoreCase("name"))) {
    						throw new IllegalArgumentException("First entry of header must be named either 'username' or 'name'");
    					}
    					if (!(header[1].equalsIgnoreCase("email"))) {
    						throw new IllegalArgumentException("Second entry of header must be named 'email'");
    					}
    					
    					while (scanner.hasNextLine()) {
    						String[] entry = scanner.nextLine().split(",");
    						System.out.println("entry length = " + entry.length);
    						if (entry.length != 2) {
    							throw new IllegalArgumentException("Error in file format, must have two columns (username, email)");
    						}
    						
    						if (userDAO.lookup(entry[0]) == null) {
	    						User newUser = new User(entry[0]);
	    						newUser.setPassword(randomPassword(6));
	    						newUser.setType(UserType.RESPONDENT);
	    						userDAO.create(newUser);
    						}
    						
    						MailingList ml = (MailingList) session.getAttribute("mailinglist");
    						MailingListData mld = new MailingListData(entry[0], ml.getMlid());
    						mld.setEmail(entry[1]);
    						mldDAO.create(mld, mlDAO, userDAO);
    					}
    					
    					input.close();
    					uploadedStream.close();
    					
    					MailingList ml = (MailingList) session.getAttribute("mailinglist");
    					MailingListData[] mld = mldDAO.getMailingListDataByMlid(ml.getMlid());
    					synchronized(session) {
    						session.setAttribute("mailinglistbody", "complete");
    						session.setAttribute("mailinglistdata", mld);
    					}
    					
    					System.out.println("fieldName = " + fieldName + "\nfileName = " + fileName + "\nisInMemory = " + isInMemory + "\nsizeInBytes = " + sizeInBytes);
    				}
    			}
    		} catch (FileUploadException e) {
    			errors.add(e.getMessage());
    			return "researcher.jsp";
    		} catch (IllegalArgumentException e) {
    			errors.add(e.getMessage());
    			return "researcher.jsp";
    		} catch (Exception e) {
    			errors.add(e.getMessage());
    			return "researcher.jsp";
    		}
    		
    		return "mailinglist.jsp";
    	}
    	
		String button = request.getParameter("button");
		
		if (button == null)
			return "mailinglist.jsp";
		
		if (button.equals("Back") || button.equals("Ok")){
			String from = (String) session.getAttribute("pageFrom");
			if (from == null)
				from = "researcher.jsp";
			synchronized(session) {
				session.removeAttribute("mailinglistbody");
				session.removeAttribute("mailinglistdata");
				session.removeAttribute("ml");
				session.removeAttribute("pageFrom");
			}
			return from;
		}
		
		if (button.equals("Create")) {
			synchronized(session) {
				session.setAttribute("mailinglistbody", "create");
			}
			return "mailinglist.jsp";
		}
		
		if (button.equals("View")) {
			try {
				String mlname = request.getParameter("value");
				MailingList ml = mlDAO.getMailingListByUseridName(user.getUserid(), mlname);
				MailingListData[] mldlist = mldDAO.getMailingListDataByMlid(ml.getMlid());
				
				synchronized(session) {
					session.setAttribute("mailinglistbody", "view");
					session.setAttribute("mailinglistdata", mldlist);
				}
				return "mailinglist.jsp";
			} catch (DAOException e) {
				errors.add(e.getMessage());
				return "errors.jsp";
			}
		}
		
		if (button.equals("Import mailing list from file") || button.equals("Create from scratch")) {
			try {
				BasicNameForm form = bnformBeanFactory.create(request);
				request.setAttribute("mailinglistform", form);
				
            	if (!form.isPresent()) {
            		return "mailinglist.jsp";
            	}
            	
        		// Validate for errors in the form
        		errors.addAll(form.checkBasicNameFormErrors());
        		if (errors.size() != 0) {
        			return "mailinglist.jsp";
        		}
				
				MailingList ml = new MailingList(mlDAO.getMlid());
				ml.setName(form.getName());
				ml.setUserid(user.getUserid());
				mlDAO.create(ml, userDAO);
				MailingList[] old_mailingList = mlDAO.getMailingListByUserid(user.getUserid());
				
				if (button.equals("Import mailing list from file")) {
					synchronized(session) {
						session.setAttribute("mailinglistbody", "import");
						session.setAttribute("mailinglist", ml);
						session.setAttribute("email_list", old_mailingList);
					}
				}
				else {
					synchronized(session) {
						session.setAttribute("mailinglistbody", "create");
						session.setAttribute("mailinglist", ml);
						session.setAttribute("email_list", old_mailingList);
					}
				}
				return "mailinglist.jsp";
			} catch (DAOException e) {
				errors.add(e.getMessage());
				return "errors.jsp";
			} catch (FormBeanException e) {
				errors.add(e.getMessage());
				return "errors.jsp";
			}
		}
		
		if (button.equals("Create More") || button.equals("Finish")) {
			try {
				SendSurveyForm form = formBeanFactory.create(request);
            	request.setAttribute("mailinglistform",form);
            	
            	if (!form.isPresent()) {
            		return "mailinglist.jsp";
            	}
            	
        		// Validate for errors in the form
        		errors.addAll(form.checkSendSurveyFormErrors());
        		if (errors.size() != 0) {
        			return "mailinglist.jsp";
        		}
        		
        		if (userDAO.lookup(form.getUserid()) == null) {
	        		User newUser = new User(form.getUserid());
	        		newUser.setPassword(randomPassword(6));
	        		newUser.setType(UserType.RESPONDENT);
	        		userDAO.create(newUser);
        		}
        		
				MailingList ml = (MailingList) session.getAttribute("mailinglist");
				MailingListData mld = new MailingListData(form.getUserid(), ml.getMlid());
				mld.setEmail(form.getEmail());
				mldDAO.create(mld, mlDAO, userDAO);
        		
        		if (button.equals("Create More")) {
        			synchronized(session) {
        				session.setAttribute("mailinglistbody", "createmore");
        			}
        			return "mailinglist.jsp";
        		}
        		else {
	        		synchronized(session) {
	        			session.setAttribute("mailinglistbody", null);
	        			session.setAttribute("mailinglist", null);
	        		}
	        		return "researcher.jsp";
        		}
			} catch (DAOException e) {
	        	errors.add(e.getMessage());
	        	return "errors.jsp";
	        } catch (FormBeanException e) {
	        	errors.add(e.getMessage());
	        	return "errors.jsp";
	        } 
		}
		
		// This command comes from createsurvey / surveysummary
		if (button.equals("Associate with this mailing list")) {
			try {
				BasicSelectForm form = bsformBeanFactory.create(request);
				request.setAttribute("mailinglistform",form);
				
	        	if (!form.isPresent()) {
	        		return "mailinglist.jsp";
	        	}
				
				Survey survey = (Survey) session.getAttribute("survey");
				if (survey == null) {
					errors.add("Invalid survey");
					return "researcher.jsp";
				}
				
				MailingList ml = mlDAO.getMailingListByUseridName(user.getUserid(), form.getType());
				MailingListData[] mldlist = mldDAO.getMailingListDataByMlid(ml.getMlid());
				
				EntityClass ec = ecDAO.lookupBySidName(survey.getSid(), "Respondents");
				// First, remove all old respondents from the Respondents node class
				Entity[] entitylist = entityDAO.getEntityByEcid(ec.getEcid());
				for (int i = 0; i < entitylist.length; i++) {
					entityDAO.delete(entitylist[i].getEid());
				}
				
				// Next, set the entity data for new Respondents
				for (int i = 1; i <= mldlist.length; i++) {
					Entity entity = new Entity(entityDAO.getEid());
					entity.setEcid(ec.getEcid());
					entity.setId("A" + i);
					entity.setName(mldlist[i-1].getRespid());
					entityDAO.create(entity, ecDAO);
				}
				
				survey.setMailinglist(form.getType());
				surveyDAO.updateMailingList(survey, mlDAO);
				
				synchronized(session) {
					session.setAttribute("ml", ml.getName());
					session.setAttribute("mailinglistbody", "associatecomplete");
					session.setAttribute("mailinglist", null);
				}
				
				return "mailinglist.jsp";
			} catch (DAOException e) {
				errors.add(e.getMessage());
				return "errors.jsp";
			} catch (FormBeanException e) {
				errors.add(e.getMessage());
				return "errors.jsp";
			}
		}
		
		errors.add("Illegal button value of " + button);
		return "errors.jsp";
    }
    
	private String randomPassword(int length) {
		String uuid = UUID.randomUUID().toString().substring(0,length);	  
		return uuid;
	}	
}
